﻿using System;
using System.Collections.Generic;
using System.Drawing.Text;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Lg.Core.Encryption
{
    public class AES:IDisposable
    {
        readonly Aes aes;
        public byte[] key { get { return aes!.Key; } }
        public AES(byte[]? key = null, byte[]? iv = null, string? mode = "ECB",int keysize = 128, string? padding = "PKCS7")
        {
            aes= Aes.Create();
            int maxKeyLength = 0;//变量，密钥长度初始变量
            #region [初始化密钥长度，默认值为256，并以长度/8作为密钥长度]
            if (keysize > 0&& keysize % 8==0)
            {
                this.aes.KeySize = keysize;
                maxKeyLength = keysize / 8;
            }
            else
            {
                throw new ArgumentException("KeySize值无效!");
            }
            #endregion
            #region [处理密钥，当长度超限则抛异常，否则将按密码标准长度填充密钥数组]
            if (key != null)
            {
                if (key.Length > keysize)
                {
                    throw new ArgumentException("密钥长度超出限制！");
                }
                byte[] keyBytes = new byte[maxKeyLength];
                for (int i = 0; i < maxKeyLength; i++)
                {
                    if (i < key.Length)
                    {
                        keyBytes[i] = key[i];
                    }
                    else
                    {
                        keyBytes[i] = 32;
                    }
                }
                this.aes.Key = keyBytes;
            }
            #endregion

            #region [处理加密模式Mode]
            if (mode != null)
            {
                switch (mode.ToUpper())
                {
                    case "CBC":
                        this.aes.Mode = CipherMode.CBC;
                        break;
                    case "CFB":
                        this.aes.Mode = CipherMode.CFB;
                        break;
                    case "CTS":
                        this.aes.Mode = CipherMode.CTS;
                        break;
                    default:
                        this.aes.Mode = CipherMode.ECB;
                        break;
                }
            }
            else
            {
                this.aes.Mode = CipherMode.ECB;
            }

            #endregion

            #region [设置PaddingMode]
            if (padding != null)
            {
                switch (padding.ToUpper())
                {
                    case "":
                        this.aes.Padding = PaddingMode.PKCS7;
                        break;
                    case "ZEROS":
                        this.aes.Padding = PaddingMode.Zeros;
                        break;
                    case "ISO10126":
                        this.aes.Padding = PaddingMode.ISO10126;
                        break;
                    case "ANSIX923":
                        this.aes.Padding = PaddingMode.ANSIX923;
                        break;
                    default:
                        this.aes.Padding = PaddingMode.PKCS7;
                        break;

                }
            }
            else
            {
                this.aes.Padding = PaddingMode.PKCS7;
            }
            #endregion
            if (iv != null)
            {
                this.aes.IV = iv;
            }
        }

        #region [公共方法]

        private void Init()
        {

        }

        public byte[] Encrypt(string data,bool dispose=false)
        {
            byte[] bytes=Encoding.UTF8.GetBytes(data);
            switch (aes!.Mode)
            {
                case CipherMode.ECB:
                    return EncryptBaseECB(bytes);
                default:
                    return EncryptBaseECB(bytes);
            }
        }
        public byte[] Encrypt(byte[] bytes, bool dispose = false)
        {
            switch (aes.Mode)
            {
                case CipherMode.ECB:
                    return EncryptBaseECB(bytes);
                default:
                    return EncryptBaseECB(bytes);
            }
        }
        public string Decrypt(byte[] data)
        {
            switch (aes!.Mode)
            {
                default:
                    return DecryptBaseECB(data);
            }
        }
        public string Decrypt(string data)
        {
            var bytes=Convert.FromBase64String(data);
            switch (aes!.Mode)
            {
                default:
                    return DecryptBaseECB(bytes);
            }
        }
        #endregion
        #region AES无向量加密
        /// <summary>  
        /// AES加密(无向量)  
        /// </summary>  
        /// <param name="plainBytes">被加密的明文</param>  
        /// <param name="key">密钥</param>  
        /// <returns>密文</returns>  
        private byte[] EncryptBaseECB(byte[] data)
        {
            using(MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cryptoStream.Write(data, 0, data.Length);
                    cryptoStream.FlushFinalBlock();
                    return ms.ToArray();
                }
            }  
        }
        #endregion 

        /// <summary>  
        /// AES解密(无向量)  
        /// </summary>  
        /// <param name="encryptedBytes">被加密的Byte</param>  
        /// <param name="key">密钥</param>  
        /// <returns>明文</returns>  
        private string DecryptBaseECB(byte[] Data)
        {
            using(MemoryStream ms = new MemoryStream(Data))
            {
                using (CryptoStream cryptoStream = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    using(StreamReader sr = new StreamReader(cryptoStream))
                    {
                        return sr.ReadToEnd();
                    } 
                }
            }
        }

        public void Dispose()
        {
            aes!.Clear();
            aes.Dispose();
        }

        /// <summary>
        /// 将字符串密钥转成Byte[]类型的AES密钥
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static byte[] ToAESKey(string str)
        {
          return  Encoding.UTF8.GetBytes(str);
        }

        public class config
        {
            public string? mode { get; set; } = "ECB";
            public byte[]? iv = null;
            public int keysize = 128;
            string? padding = "PKCS7";
        }
    }
}
